package org.zn.note.jdk.thread;

import org.zn.note.common.util.ThreadUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName BaseThread
 * @Author zn
 * @Date 2019/4/1 9:38
 **/
/*
1、Linux内核还在持续更新完善，进程和线程的实现模块也是内核完善任务之一。
2、线程数受内存（JVM堆内存、线程Stack内存 。。。）、操作系统线程数影响。（主要是内存）
   /proc/sys/kernel/threads-max    -Xms   -Xmx   -Xss
   32位Linux单进程最大4G （^2^32）（核心态1G、用户态3G），大概线程数 3W 吧
   64位理论上 2^64（几乎无限大）。实际可能是 2^36 （大概64G）
Thread.yield()  不释放锁
Thread.sleep()  不释放锁
Object.wait()   释放锁
Object.notify() 不释放锁
Thread.join()   是用 Object.wait() 实现的
 */
public class BaseThread {

    private static final Object lock = new Object();

    public static void main(String[] args) {
        new BaseThread().testJoin();
    }

    // wait 释放锁，notify 不释放锁，两者都需要获取 object的锁
    // 这也可以理解，如果wait后不释放锁，那么外面获取不到锁，又怎么notify呢
    private void testWait() {
        new Thread(new TaskWait()).start();
        ThreadUtil.sleep(TimeUnit.SECONDS, 1L);
        synchronized (lock) {
            lock.notify();
            ThreadUtil.sleep(TimeUnit.SECONDS, 1L);
            System.out.println("testWait");
        }
    }

    private static class TaskWait implements Runnable {
        @Override
        public void run() {
            try {
                synchronized (lock) {
                    System.out.println("TaskWait Start.");
                    lock.wait(); // object.wait 必须先获取 object 的锁
                    System.out.println("TaskWait End.");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 为什么起名 join呢
    // 就是将本来并行的Thread串行了，就好像是合并了
    private void testJoin() {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName());
                    ThreadUtil.sleep(TimeUnit.SECONDS, 1L);
                }
            }
        }, "Thread-1");
        thread1.start();
        Thread.currentThread().setName("Thread-Main");
        System.out.println(Thread.currentThread().getName());
        try {
//            thread1.join(); // 直到 thread1 执行完毕，本线程继续执行
            thread1.join(1000L); // thread1执行完毕 或 定时到了，则本线程继续执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }

    // Thread.yield(); 不释放锁
    // Thread.sleep(); 不释放锁
    private void testLock() {
        new Thread(new TaskLock(), "Thread-1").start();
        new Thread(new TaskLock(), "Thread-2").start();
    }

    private static class TaskLock implements Runnable {
        @Override
        public void run() {
            synchronized (TaskLock.class) {
                while (true) {
                    System.out.println(Thread.currentThread().getName());
//                    Thread.yield(); // 不释放锁
                    try {
//                        TimeUnit.SECONDS.sleep(1); // 不释放锁
                        Thread.sleep(1000L); // 不释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // 优先级可以设置为 1-10，不同操作系统支持的不同，不建议直接写数字
    private void testPriority() {
        int maxSize = 10000000;
        List list = new ArrayList();
        Thread threadMinPriority = new Thread(new TaskPriority(list, 1, maxSize));
        threadMinPriority.setPriority(Thread.MIN_PRIORITY);
        Thread threadNormPriority = new Thread(new TaskPriority(list, 2, maxSize));
        threadNormPriority.setPriority(Thread.NORM_PRIORITY);
        Thread threadMaxPriority = new Thread(new TaskPriority(list, 3, maxSize));
        threadMaxPriority.setPriority(Thread.MAX_PRIORITY);
        threadMinPriority.start();
        threadNormPriority.start();
        threadMaxPriority.start();
        while (list.size() < maxSize) {
            ThreadUtil.sleep(TimeUnit.SECONDS, 3L);
        }
        System.out.println(sumList(list));
    }

    // 不用与外部类交互
    private static class TaskPriority implements Runnable {
        private int threadNo;
        private List list;
        private int maxSize;

        TaskPriority(List list, int threadNo, int maxSize) {
            this.list = list;
            this.threadNo = threadNo;
            this.maxSize = maxSize;
        }

        @Override
        public void run() {
            while (list.size() < maxSize) {
                synchronized (Task.class) {
                    if (list.size() < maxSize) { // dubbo check
                        list.add(threadNo);
                    }
                }
            }
        }
    }

    private Map sumList(List list) {
        Map resultMap = new HashMap();
        for (Object o : list) {
            Object obj = resultMap.get(o);
            if (obj != null) {
                resultMap.put(o, ((Integer) obj + 1));
            } else {
                resultMap.put(o, 1);
            }
        }
        return resultMap;
    }
}